﻿using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Framework.Exceptions;
using Framework.Exceptions.RepositoryExceptions;
using Interfaces.BusinessLogic;
using Interfaces.Models;
using Interfaces.Repositories;
using Interfaces.RepositoryModels.InternalModels.UserRoleModels;

namespace BusinessLogic.Services.Mapping
{
    public class UserMapper: IEntityMapper<IUser,UserModel>, IEntityMapper<UserModel, IUser>
    {
        private readonly IRoleRepository _roleRepository;
        private readonly IUserRepository _userRepository;
        
        public UserMapper(IRoleRepository roleRepository, IUserRepository userRepository)
        {
            _roleRepository = roleRepository;
            _userRepository = userRepository;
        }

        private static void CreateInMapping()
        {
            Mapper.Reset();
            Mapper.CreateMap<IRole, RoleModel>();
            Mapper.CreateMap<IUser, UserModel>()
                .ForMember(x => x.Roles, opt => opt.Ignore());
        }

        private static void CreateOutMapping()
        {
            Mapper.Reset();
            Mapper.CreateMap<UserModel, IUser>();
            Mapper.CreateMap<RoleModel, IRole>()
                  .ForMember(x => x.Users, opt => opt.Ignore());
        }

        public UserModel Map(IUser user)
        {

            CreateInMapping();
            UserModel newUser = null;

            try
            {
                var userRoles = user.Roles.Select(x => _roleRepository.GetByType(x.Type)).ToList();
                newUser = _userRepository.GetById(user.Id);

                if (newUser == null)
                {
                    newUser = new UserModel();

                    Mapper.Map(user, newUser);
                    newUser.CreatedDate = DateTime.Now;
                    newUser.ChangedDate = DateTime.Now;
                    newUser.Roles = userRoles;
                    foreach (var roleModel in userRoles)
                        roleModel.Users.Add(newUser);
                }
                else
                {
                    Mapper.Map(user, newUser);
                    newUser.ChangedDate = DateTime.Now;
                    foreach (var roleModel in userRoles)
                    {
                        if (!newUser.Roles.Any(x => x.Id.Equals(roleModel.Id)))
                            newUser.Roles.Add(roleModel);
                    }
                }

                
            }
            catch(EntityNotFoundException e)
            {
                if (ExceptionHandlingManager.HandleException(e, PolicyNames.DALPolicy)) 
                    throw ;
            }

            return newUser;
        }

        public IUser Map(UserModel entity)
        {
            IUser user = null;

            try
            {
                CreateOutMapping();
                user = Mapper.Map<UserModel, IUser>(entity);
            }
            catch (Exception exception)
            {
                if (ExceptionHandlingManager.HandleException(exception, PolicyNames.DALPolicy))
                    throw;
            }

            return user;
        }
    }
}
